<?php

namespace App\Services\Tools;

use App\Enums\RedisKeyEnum;
use App\Exceptions\BasicException;
use App\Jobs\RongCloud\BroadcastPushJob;
use App\Jobs\RongCloud\GroupPushJob;
use App\Jobs\RongCloud\RoomPushJob;
use App\Jobs\RongCloud\UserPushJob;
use RongCloud\RongCloud;

class RongCloudService
{

    public function __construct()
    {
        $this->client = new RongCloud(config('rongcloud.app_key'), config('rongcloud.app_secret'), config('rongcloud.api_url'));
    }

    /**
     * 异步队列推送
     * @param $senderId
     * @param $targetId
     * @param $content
     * @param int $delay
     */
    public function queue($senderId, $targetId, $content, $delay = 0, $type = 'RC:CmdMsg', $isIncludeSender = 0)
    {
        $isBroadcast = false;
        if($targetId)
        if ($this->isRoom($targetId)) {
            $job = new RoomPushJob($senderId, $targetId, $content, $type);
            //dispatch($job->delay($delay));
            dispatch($job->delay($delay))->onQueue("isRoomPush");
        } else if ($this->isUser($targetId)) {
            $job = new UserPushJob($senderId, $targetId, $content, $type, $isIncludeSender);
            //dispatch($job->delay($delay));
            dispatch($job->delay($delay))->onQueue("isUserPush");
        } else if ($this->isBroadcast($targetId)) {
            $isBroadcast = true;
            $job = new BroadcastPushJob($senderId, $content, $type);
            $res = dispatch($job->delay($delay))->onQueue("isBroadcastPush");
            //$res = dispatch($job->delay($delay));
        } else if ($this->isGroup($targetId)){
            $job = new GroupPushJob($senderId, $targetId, $content, $type);
            dispatch($job->delay($delay));
            //dispatch($job->delay($delay))->onQueue("isGroupPush");
        }
        if($isBroadcast){
            $queueLumenTime = HelperService::microtime_float();
            $data = [
                'senderId' => $senderId,//发送人 id
                'targetId' => $targetId,//聊天室 id
                "objectName" => $type,//消息类型 文本
                'content' => json_encode($content) //消息内容
            ];
            try{
                $this->recordBroadcastLogByLumenQueue($data,$res,$queueLumenTime);
            }catch (\Exception $e){

            }
        }
    }

    //房间项目调用lumen队列进行消费广播
    public function recordBroadcastLogByLumenQueue($data,$queueRes,$queueLumenTime=0){
        $targetId = $data['targetId'];
        $objectName = $data['objectName'];
        $content = $data['content'];
        $content = empty($content)?[]:json_decode($content,true);
        $uniKey = $content['uni_key'] ??'';
        if($targetId != 'room'){    //是否是广播消息
            return true;
        }
        if($objectName == 'RC:CmdMsg'){ //数据结构不统一
            $msgType = $content['data']['type']??0;
        }else{
            $extra = $content['extra']??'';
            $msgType = $extra['type']??0;
        }

        $sendRes = $queueRes?2:5;  //发送结果 1表示发送成功 2表示推送进队列待处理 3表示融云处理失败 4表示队列处理失败 5表示推送队列失败
        $dbData = [
            'origin_data' =>json_encode($data),
            'send_res' => $sendRes,
            'uni_key' => $uniKey,
            'error_msg' => '',
            'msg_type' => $msgType,
            'queue_ry_time' => 0,
            'queue_lumen_time' => $queueLumenTime,
        ];
        app('model_broadcast_ry_log')->insert($dbData);
        return  true;
    }


    /**
     * 自适应同步推送
     * @param $senderId
     * @param $targetId
     * @param $content
     * @return array
     */
    public function push($senderId, $targetId, $content, $type = 'RC:CmdMsg')
    {
        $result = [];
        if ($this->isRoom($targetId)) {
            $result = $this->roomPush($senderId, $targetId, $content, $type);
        } else if ($this->isUser($targetId)) {
            $result = $this->userPush($senderId, $targetId, $content, $type);
        } else if ($this->isBroadcast($targetId)) {
            $result = $this->broadcastPush($senderId, $content, $type);
        }
        return $result;
    }

    /**
     * 房间同步推送
     * @param $senderId
     * @param $targetId
     * @param $content
     * @return array
     */
    public function roomPush($senderId, $targetId, $content, $type = 'RC:CmdMsg')
    {
        $result = $this->client->getMessage()->Chatroom()->send([
            'senderId' => $senderId,
            'targetId' => $targetId,
            'objectName' => $type,
            'content' => json_encode($content),
        ]);

        return $result;
    }

    /**
     * 用户同步推送
     * @param $senderId
     * @param $targetId
     * @param $content
     * @return array
     */
    public function userPush($senderId, $targetId, $content, $type = 'RC:CmdMsg', $isIncludeSender = 0)
    {
        $message = [
            'senderId' => $senderId,
            'targetId' => $targetId,
            'objectName' => $type,
            'content' => json_encode($content),
            "isIncludeSender" => $isIncludeSender
        ];
        $result = $this->client->getMessage()->Person()->send($message);

        return $result;
    }

    /**
     * 全局同步推送
     * @param $senderId
     * @param $content
     * @return array
     */
    public function broadcastPush($senderId, $content, $type = 'RC:CmdMsg')
    {
        $result = $this->client->getMessage()->Chatroom()->broadcast([
            'senderId' => $senderId,
            'objectName' => $type,
            'content' => json_encode($content),
        ]);

        return $result;
    }

    public function isRoom($topic)
    {
        $prefix = substr($topic, 0, 5);
        if ($prefix === 'room_' || $prefix === 'theme') {
            return true;
        }
        return false;
    }

    public function isUser($topic)
    {
        // 用于多人的推送
        if (is_array($topic)) {
            return true;
        }
        if (substr($topic, 0, 5) === 'user_') {
            return true;
        }
        return false;
    }

    public function isBroadcast($topic)
    {
        if ($topic === 'room') {
            return true;
        }
        return false;
    }

    public function getRoomName($roomId)
    {
        return 'room_' . $roomId;
    }

    public function getUserName($userId)
    {
        return 'user_' . $userId;
    }

    public function getBroadcast()
    {
        return 'room';
    }

    /**
     * 创建用户获取 Token
     * @param $userId
     * @param $name
     * @param string $avatar
     * @return array
     */
    public function createUser($userId, $name, $avatar = 'https://')
    {
        $user = [
            'id' => 'user_' . $userId,
            'name' => $name,//用户名称
            'portrait' => $avatar //用户头像
        ];
        $result = $this->client->getUser()->register($user);
        return $result;
    }

    /**
     * 用户白名单
     * @param $userId
     * @param $userIdArr
     * @return array
     */
    public function whitelist($userId,$userIdArr)
    {
        $toUserId = 'user_' . $userId;
        $data = [
            'userId' => $toUserId,
        ];
        foreach ($userIdArr as $userId) {
            $data['whiteUserId']= 'user_' . $userId;
        }
        return $this->client->getUser()->newWhitelist($data);
    }

    /**
     * 用户白名单
     * @param $userId
     * @param $userIdArr
     * @return array
     */
    public function whitelistADD($userId,$userIdArr)
    {
        $toUserId = 'user_' . $userId;
        $data = [
            'userId' => $toUserId,
        ];
        foreach ($userIdArr as $userId) {
            $data['whiteUserId']= 'user_' . $userId;
        }
        return $this->client->getUser()->newWhitelistADD($data);
    }

    /**
     * 创建房间
     * @param $id
     * @param $name
     * @return mixed|null
     * 创建融云房间
     */
    public function createRoom($room_id, $name)
    {
        return $this->client->getChatroom()->create([
            'id' => $room_id,
            'name' => $name,
        ]);
    }

    /**
     * 销毁房间
     * @param $roomId
     * @return mixed|null
     * 销毁融云房间
     */
    public function destroyRoom($roomId)
    {
        $result = $this->client->getChatroom()->destory([
            'id' => 'room_' . $roomId,
        ]);
        return $result;
    }

    /**
     * 获取房间信息
     * @param $roomId
     * @return mixed|null
     */
    public function getRoom($roomId)
    {
        $result = $this->client->getChatroom()->get([
            'id' => 'room_' . $roomId,
        ]);
        return $result;
    }

    /**
     * 获取历史消息
     */
    public function getHistoryChatLog($date="",$isCheck=true)
    {
        $date = "2021062114";
        if(empty($date)){
            $timestamp = strtotime("-1 hour");
            $date = date('YmdH', $timestamp);
        }
        //解压后的文件名
        $unzipFilename = date('Y-m-d-H',strtotime($date));
        //文件保存路径
        $path = storage_path('logs/chat');

        if($isCheck){
            $result = $this->client->getMessage()->History()->get(['date'=> $date]);
            if($result['code'] == 200){
                $zipPath = $result['url'];
                if(!file_exists($path)){
                    mkdir($path,0777,true);
                }
                //下载zip文件到本地
                $bool = $this->downloadFile($zipPath, $path, $unzipFilename);
                if (!$bool) return ['status' => 0, 'msg' => '文件下载失败'];

                //解压文件
                $bool = $this->unzip($unzipFilename . '.zip', $path);
                if (!$bool) return ['status' => 0, 'msg' => '文件解压失败'];

                //获取数据
                $data = [];
                $this->getData($path . $unzipFilename, $data);
                return ['status' => 1, 'msg' => '获取成功', 'data' => $data];
            }
        }
        die;

    }

    /**
     * 下载文件
     * @param string $downloadUrl 下载链接
     * @param string $path 文件保存路径
     * @param string $filename 文件保存名称
     * @return int|false
     */
    private function downloadFile($downloadUrl, $path, $filename)
    {
        return file_put_contents($path . $filename . '.zip', file_get_contents($downloadUrl));
    }

    /**
     * 解压zip
     * @param string $filename 要解压的文件名
     * @param string $path 要解压的文件所在路径，同时也是解压后文件的保存路径
     * @return bool
     */
    private function unzip($filename, $path) {
        $zip = new \ZipArchive();

        if (empty($filename) || empty($path)) {
            return false;
        }

        if ($zip->open($path . $filename) === true) {
            $zip->extractTo($path);
            $zip->close();
            //解压完成删除zip文件
            unlink($path . $filename);
            return true;
        } else {
            return false;
        }
    }

    //从文件中获取数据
    private function getData($file, &$data)
    {
        $data = file_get_contents($file);
        $data = explode("\r\n", $data);
        foreach ($data as $k => &$v) {
            if ($v) $v = json_decode(substr($v, 19), true);
            else unset($data[$k]);
        }
    }

    public function getGroupNamePrefix():string
    {
        return "group_";
    }

    public function getGroupName(int $groupId):string
    {
        return $this->getGroupNamePrefix() . $groupId;
    }

    public function isGroup($topic)
    {
        if (substr($topic, 0, 6) === $this->getGroupNamePrefix()) {
            return true;
        }
        return false;
    }

    // 获取群组
    public function getGroup($groupId)
    {
        return $this->client->getGroup()->get([
            'id' => $this->getGroupName($groupId),
        ]);
    }

    // 群消息推送
    public function groupPush($senderId, $targetId, $content, $type = 'RC:CmdMsg')
    {
        $message = [
            'senderId' => $senderId,
            'targetId' => $targetId,
            'objectName' => $type,
            'content' => $content,
            "isIncludeSender" => 1
        ];
        return $this->client->getMessage()->Group()->send($message);
    }

    // 创建群聊
    public function createGroup(int $id, string $name, int $ownerId)
    {
        return $this->client->getGroup()->create([
            'id'=> $this->getGroupName($id),//群组 id
            'name'=> $name,//群组名称
            'members'=>[          //群成员 列表
                'id'=> $this->getUserName($ownerId)
            ]
        ]);
    }

    // 加入群聊
    public function joinGroup(int $id, array $userIds)
    {
        $users = [];
        foreach ($userIds as $userId){
            $users['id'][] = $this->getUserName($userId);
        }
        return $this->client->getGroup()->joins([
            'id'=> $this->getGroupName($id),//群组 id
            'member'=>$users,//群成员信息
        ]);
    }

    // 退出群聊
    public function quitGroup(int $id, array $userIds)
    {
        $users = [];
        foreach ($userIds as $userId){
            $users['id'][] = $this->getUserName($userId);
        }
        return $this->client->getGroup()->quit([
            'id'=> $this->getGroupName($id),
            'member'=>$users,//群成员信息
        ]);
    }

    public function recallGroupMessage(string $uid, int $userId, int $targetId, int $timestamp)
    {
        $isAdmin = $userId == 0 ? 1: 0;
        return $this->client->getMessage()->Group()->recall([
            'senderId'=> $this->getUserName($userId),//发送人 Id
            'targetId'=> $this->getGroupName($targetId),//群组 Id
            "uId"=>$uid,//消息的唯一标识
            'sentTime'=>$timestamp,//消息的发送时间
            "isAdmin" => $isAdmin,
        ]);
    }

    /**
     * 更新指定会话的消息免打扰状态
     *
     * @param string $type 会话类型: PRIVATE/GROUP/DISCUSSION/SYSTEM
     * @param int $userId 用户 id
     * @param int $groupId 群组 id
     * @param int $isDnd 是否设置为免打扰: 0=否; 1=是;
     * @return int
     */
    public function conversationMuteStatus(string $type, int $userId, int $groupId, int $isDnd): int
    {
        $conversation = [
            'type' => $type,
            'userId' => $this->getUserName($userId),
            'targetId' => $this->getGroupName($groupId),
        ];
        if ($isDnd) {
            $res = $this->client->getConversation()->mute($conversation);
        } else {
            $res = $this->client->getConversation()->unmute($conversation);
        }
        return $res['code'];
    }

    public function blockUser($userId, $minute){
        $this->client->getUser()->Block()->add(['id' => $userId, "minute" => $minute]);
    }

    public function getBlockUserList(){
        return $this->client->getUser()->Block()->getList();
    }
    public function removeBlockUser($userId){
        $this->client->getUser()->Block()->remove(['id' => "user_" . $userId]);
    }

    /**
     * @return array
     */
    public function systemPushUser($senderId, $targetId, $content, $type = 'RC:CmdMsg'){
        $message = [
            'senderId'=> $senderId,//发送人 id
            'targetId'=> $targetId,//接收人 id
            "objectName"=>$type,//消息类型 文本
            'content' => $content//消息体
        ];


        $result = $this->client->getMessage()->System()->send($message);
        return $result;

    }
}
